module EventMachine
  module WebSocket
    class Connection
      attr_accessor :loginname, :current_opponent, :current_friend_loginname, :pvp_state, :pvp1_wins, :matching_retry_times,
        :current_battle, :current_win_rounds, :current_action

      IDLE = 1
      MATCHING = 2
      BATTLING = 3

      def simple_login(loginname, players)
        if loginname.nil? || loginname.empty?
          loginname = players['takafan'] ? 'ayumi' : 'takafan'
        end
        
        old_ws = players[loginname]
        if old_ws && old_ws != self
          old_ws.logout players, '你在别的地方登录了'
        end
        players[loginname] = self
        @loginname = loginname
        @current_opponent = nil
        @pvp_state = IDLE
        @pvp1_wins = 0
        send_message_simple_logined
        puts "#{loginname} logined, players.size: #{players.size}"
      end

      def logout(players, reason = nil)
        if @loginname
          loginname = @loginname
          escape_pvp
          cancel_matching

          @loginname = nil
          @pvp1_wins = 0
          send_message_loggedout(reason)

          players.delete loginname
          puts "#{loginname} logged out, players.size: #{players.size}"

          loginname
        end
      end

      # 随机对战
      def pvp1(players)
        if @loginname && players[@loginname]
          @pvp_state = MATCHING
          @matching_retry_times = 0
          send_message_pvp1_ready
          puts "#{@loginname} random battle ready, state: #{@pvp_state}"

          matching1(players)
        end
      end

      # 好友对战
      def pvp2(friend_loginname, players)
        if @loginname && players[@loginname] && friend_loginname && !friend_loginname.empty? && @loginname != friend_loginname
          @pvp_state = MATCHING
          @matching_retry_times = 0
          @current_friend_loginname = friend_loginname
          send_message_pvp2_ready friend_loginname
          puts "#{@loginname} friend battle ready, state: #{@pvp_state}"

          matching2(players)
        end
      end

      def cancel_matching(reason = nil)
        if @pvp_state == MATCHING
          friend_loginname = @current_friend_loginname
          @pvp_state = IDLE
          @current_friend_loginname = nil
          send_message_matching_canceled(reason)

          friend_loginname
        end
      end

      def escape_pvp
        if @pvp_state == BATTLING && @current_opponent
          @current_opponent.win("#{@loginname} 逃跑了")
        end
      end

      def win(reason = nil)
        @current_battle = nil
        @pvp_state = IDLE
        if @current_friend_loginname
          @current_friend_loginname = nil
        else
          @pvp1_wins += 1
        end
        send_message_won(reason)
        @current_opponent.current_battle = nil
        @current_opponent.pvp_state = IDLE
        @current_opponent.current_friend_loginname = nil
        @current_opponent.send_message_lost
      end

      def stjzb(action)
        @current_battle.act(self, action) if @current_battle
      end

      def battling!
        @pvp_state = BATTLING
      end

      def send_message_welcome
        send_message 'msg1', "欢迎来到 石头剪子布 大战！"
      end

      def send_message_simple_logined
        send_message 'simple-logined', @loginname
      end

      def send_message_loggedout(reason = nil)
        send_message 'loggedout', reason || '已退出'
      end

      def send_message_pvp1_ready
        send_message 'pvp-ready', '匹配对手中'
      end

      def send_message_pvp2_ready(friend_loginname)
        send_message 'pvp-ready', "匹配 #{friend_loginname} 中"
      end

      def send_message_matching
        send_message 'matching', '.'
      end

      def send_message_matching_canceled(reason = nil)
        part = '匹配被取消'
        send_message 'matching-canceled',
          reason ? [ reason, part ].join(', ') : part
      end

      def send_message_matched(instruction)
        send_message 'matched', "#{@loginname} 对 #{@current_opponent.loginname}, #{instruction}"
      end

      def send_message_won(reason = nil)
        word = '赢了!'
        send_message 'won', 
          [ 
            reason ? [ reason, word ].join(', ') : word, 
            @pvp1_wins
          ]
      end

      def send_message_lost
        send_message 'lost', '输了。'
      end

      def send_message_round_finished(round, compare)
        send_message 'round-finished',
          [ round, compare, @loginname, @current_action, @current_win_rounds, @current_opponent.loginname, @current_opponent.current_action, @current_opponent.current_win_rounds ]
      end

      private

      # pvp1匹配，隔3秒主动匹配1次，重试10次，不成功cancel
      def matching1(players)
        EM.add_timer(3) {
          if @loginname && @pvp_state == MATCHING
            puts "#{@loginname} matching, retry: #{@matching_retry_times}"
            opponent = players.values.select{|_ws| _ws != self and _ws.pvp_state == MATCHING and _ws.current_friend_loginname.nil? }.sample
            if opponent
              StjzbServer::Stjzb.new(self, opponent)
            elsif @matching_retry_times < 10
              send_message_matching
              @matching_retry_times += 1
              matching1(players)
            else
              cancel_matching('没有找到对手')
              puts "no opponent, matching canceled, state: #{@pvp_state}"
            end
          else
            puts "ignore matching"
          end
        }
      end

      # pvp2匹配
      def matching2(players)
        puts "#{@loginname} matching #{@current_friend_loginname}, retry: #{@matching_retry_times}"
        if @pvp_state == MATCHING
          opponent = players[@current_friend_loginname]
          if opponent && opponent.pvp_state == MATCHING && opponent.current_friend_loginname == @loginname
            StjzbServer::Stjzb.new(self, opponent)
          elsif @matching_retry_times < 10
            send_message_matching
            @matching_retry_times += 1
            EM.add_timer(3) {
              matching2(players)
            }
          else
            friend_loginname = cancel_matching("#{@current_friend_loginname} 没有反应")
            puts "#{friend_loginname} not pong, matching canceled, state: #{@pvp_state}"
          end
        else
          puts "ignore, state: #{@pvp_state}"
        end
      end

      def send_message(act, msg)
        send Oj.dump([ act, msg ])
      end

    end
  end
end
